package com.liyunc.demo.bundle.automation.service;

import com.liyunc.demo.comp.common.db.TransactionHook;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author liyuncong
 * @version 1.0
 * @file TransactionHookService
 * @brief TransactionHookService
 * @details TransactionHookService
 * @date 2022-03-21
 *
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2022-03-21               liyuncong          Created
 */
public class TransactionHookService implements TransactionHook {
    private static final int INITIAL_SIZE = 5;
    private static final int MAX_JOB_PENDING = 5000;
    private static final ThreadLocal<Set<Runnable>> AFTER_TRANSACTION_CALLS =
        ThreadLocal.withInitial(() -> new HashSet<>(INITIAL_SIZE));
    private static final int THREAD_POOL_SIZE = 1;
    private static final ExecutorService SINGLE_THREAD_EXECUTOR =
        new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE,
            60L, TimeUnit.MINUTES,
            new ArrayBlockingQueue<>(MAX_JOB_PENDING),
            new ThreadPoolExecutor.CallerRunsPolicy());

    @Override
    public void afterTransaction(Runnable runnable) {
        AFTER_TRANSACTION_CALLS.get().add(runnable);
    }

    public void clear() {
        AFTER_TRANSACTION_CALLS.set(new HashSet<>(INITIAL_SIZE));
    }

    /**
     * invokeAll.
     */
    public void invokeAll() {
        List<Runnable> taskList = AFTER_TRANSACTION_CALLS
            .get().stream().toList();
        SINGLE_THREAD_EXECUTOR.submit(() -> taskList.forEach(SINGLE_THREAD_EXECUTOR::submit));
    }
}
